from django.contrib import admin
from .models import Question, ExamRoom, Examinee, ExamPaper, ExamRegistration, Subject, ExamNotification
from django.utils.safestring import mark_safe
from django.utils.html import format_html
from django.utils import timezone
from django.contrib import messages
from django_celery_beat.models import PeriodicTask, CrontabSchedule
from django.shortcuts import render, redirect
from django.urls import path
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from django.conf import settings
import os
import json
from .import_handlers import parse_excel, parse_word, import_from_word

# Class ExamRoomAdmin(admin.ModelAdmin):

class SubjectAdmin(admin.ModelAdmin):
    list_display = ('name', 'description', 'created_at', 'updated_at', 'question_count')
    search_fields = ('name', 'description')
    list_filter = ('created_at', 'updated_at')
    readonly_fields = ('created_at', 'updated_at')

    def question_count(self, obj):
        return obj.questions.count()
    question_count.short_description = '题目数量'

class QuestionAdmin(admin.ModelAdmin):
    change_list_template = 'admin/question_changelist.html'
    list_display = ('id', 'subject', 'get_content_short', 'question_type', 'difficulty', 'creator', 'update_time', 'get_image_preview')
    list_filter = ('subject', 'question_type', 'difficulty', 'creator')
    search_fields = ('content', 'subject', 'creator')
    readonly_fields = ('create_time', 'update_time', 'get_image_preview')
    fieldsets = (
        ('基本信息', {
            'fields': ('subject', 'content', 'question_type', 'difficulty')
        }),
        ('答案与选项', {
            'fields': ('options', 'answer')
        }),
        ('附加信息', {
            'fields': ('image', 'get_image_preview', 'creator', 'create_time', 'update_time')
        }),
    )

    def get_content_short(self, obj):
        """显示题干的前20个字符"""
        if len(obj.content) > 20:
            return f"{obj.content[:20]}..."
        return obj.content
    get_content_short.short_description = '题干'

    def get_image_preview(self, obj):
        if obj.image:
            return mark_safe(f'<img src="{obj.image.url}" width="100" height="auto" />')
        return "无图片"
    get_image_preview.short_description = '图片预览'

    def get_image_name(self, obj):
        """获取图片名称"""
        return obj.image_name if obj.image_name else '无图片'
    get_image_name.short_description = '图片名称'

    def save_model(self, request, obj, form, change):
        if not obj.creator:
            obj.creator = request.user.username
        super().save_model(request, obj, form, change)

    def get_urls(self):
        urls = super().get_urls()
        custom_urls = [
            path('import/', self.import_questions, name='question_import'),
        ]
        return custom_urls + urls

    def import_questions(self, request):
        step = 1
        context = {
            'step': step,
            'opts': self.model._meta,
            'has_permission': True,
            'site_url': '/',
            'original': None,
            'is_popup': False,
            'save_as': False,
            'has_delete_permission': False,
            'has_add_permission': False,
            'has_change_permission': True,
            'title': '导入试题',
        }

        if request.method == 'POST':
            step = int(request.POST.get('step', 1))

            if step == 1 and request.FILES.get('file'):
                file = request.FILES['file']
                file_extension = os.path.splitext(file.name)[1].lower()

                if file_extension not in ['.xlsx', '.xls', '.docx','.doc']:
                    self.message_user(request, '不支持的文件格式。请上传 Excel 或 Word 文件。', level=messages.ERROR)
                    return render(request, 'admin/import_questions.html', context)

                # 保存上传的文件
                file_path = default_storage.save(f'temp/{file.name}', ContentFile(file.read()))
                file_full_path = os.path.join(settings.MEDIA_ROOT, file_path)

                # 处理预览数据
                if file_extension in ['.xlsx', '.xls']:
                    preview_data = parse_excel(file_full_path)[:5]  # 只预览前5条数据
                else:
                    # 处理 Word 文件预览
                    preview_data = parse_word(file_full_path)[:5]

                context.update({
                    'step': 2,
                    'file_path': file_path,
                    'preview_data': preview_data,
                    'subjects': Subject.objects.all()
                })
                return render(request, 'admin/import_questions.html', context)

            elif step == 2:
                subject_id = request.POST.get('subject')
                file_path = request.POST.get('file_path')
                if not file_path:
                    self.message_user(request, '文件路径未找到，请重新上传文件。', level=messages.ERROR)
                    return render(request, 'admin/import_questions.html', {'step': 1})

                file_full_path = os.path.join(settings.MEDIA_ROOT, file_path)
                if not os.path.exists(file_full_path):
                    self.message_user(request, '文件不存在，请重新上传文件。', level=messages.ERROR)
                    return render(request, 'admin/import_questions.html', {'step': 1})

                try:
                    subject = Subject.objects.get(id=subject_id)
                    file_extension = os.path.splitext(file_full_path)[1].lower()

                    # 从EXCEL文件中导入
                    if file_extension in ['.xlsx', '.xls']:
                        questions = parse_excel(file_full_path)
                        # 导入试题
                        for question_data in questions:
                            Question.objects.create(
                                subject=subject,
                                content=question_data['content'],
                                question_type=question_data['question_type'],
                                options=question_data['options'],
                                answer=question_data['answer'],
                                image=question_data['image'],
                                image_name=question_data.get('image_name'),
                                difficulty=question_data['difficulty']
                            )
                        imported_count = len(questions)

                    # 从WORD文件中导入
                    else:
                        imported_count = import_from_word(file_full_path, subject_id)

                    context.update({
                        'step': 3,
                        'success': True,
                        'imported_count': imported_count,
                        'error_count': 0
                    })
                    self.message_user(request, f'成功导入 {imported_count} 道试题！')
                except Exception as e:
                    context.update({
                        'step': 3,
                        'success': False,
                        'errors': [str(e)]
                    })
                    self.message_user(request, f'导入失败：{str(e)}', level=messages.ERROR)
                finally:
                    # 删除临时文件
                    try:
                        if os.path.exists(file_full_path):
                            try:
                                os.remove(file_full_path)
                            except PermissionError:
                                print(f"警告：无法删除临时文件 {file_full_path}，可能被其他程序占用")
                            except Exception as e:
                                print(f"删除临时文件时出错: {str(e)}")
                    except Exception as e:
                        print(f"清理过程中出错: {str(e)}")

                return render(request, 'admin/import_questions.html', context)

        return render(request, 'admin/import_questions.html', context)

admin.site.register(Question, QuestionAdmin)
admin.site.register(Subject, SubjectAdmin)

class ExamineeAdmin(admin.ModelAdmin):
    list_display = ('name', 'phone', 'nickname', 'gender', 'email', 'organization', 'register_time', 'last_login')
    list_filter = ('gender', 'register_time', 'last_login')
    search_fields = ('name', 'phone', 'nickname', 'email', 'organization', 'id_card')
    readonly_fields = ('register_time', 'last_login')
    fieldsets = (
        ('基本信息', {
            'fields': ('name', 'phone', 'nickname', 'gender', 'email', 'organization', 'id_card')
        }),
        ('账户信息', {
            'fields': ('password', 'register_time', 'last_login')
        }),
    )

    def save_model(self, request, obj, form, change):
        if not change:  # 只在创建新用户时设置密码
            obj.password = form.cleaned_data["password"]
        super().save_model(request, obj, form, change)

admin.site.register(Examinee, ExamineeAdmin)

@admin.register(ExamRoom)
class ExamRoomAdmin(admin.ModelAdmin):
    class Media:
        css = {
            'all': ('exam_system/css/admin_custom.css',)
        }
        js = ('admin/js/jquery.init.js', 'exam_system/js/admin_examroom.js',)

    fieldsets = (
        ('基本信息', {
            'fields': ('name', 'exam_type', 'start_time', 'duration', 'invigilators'),
            'description': '注意：考试开始时间必须至少在当前时间的1分钟之后。新增考场状态默认为"准备中"。'
        }),
        ('考试科目', {
            'fields': ('subject_1', 'subject_2', 'subject_3'),
            'description': '科目一为必填项，科目二和科目三为选填项。多个科目的试题将组成综合试卷。'
        }),
        ('题目配置', {
            'fields': (
                'single_choice_count', 'single_choice_score',
                'multiple_choice_count', 'multiple_choice_score',
                'judgment_count', 'judgment_score'
            ),
            'description': '请确保题库中有足够的题目数量。系统会自动检查题目是否充足。'
        }),
        ('考试统计', {
            'fields': ('total_score', 'average_score', 'created_at', 'updated_at'),
            'description': '总分会根据题目配置自动计算。'
        }),
    )
    list_display = ('name', 'get_subjects', 'exam_type', 'start_time', 'duration', 'total_score',
                   'average_score', 'get_status_with_color', 'get_question_counts')
    list_filter = ('status', 'subject_1', 'subject_2', 'subject_3', 'exam_type', 'start_time')
    search_fields = ('name', 'exam_type', 'invigilators')
    readonly_fields = ('total_score', 'average_score', 'created_at', 'updated_at')

    def get_form(self, request, obj=None, **kwargs):
        form = super().get_form(request, obj, **kwargs)
        # 只有当 'total_score' 在表单字段中时才设置为只读
        if 'total_score' in form.base_fields:
            form.base_fields['total_score'].widget.attrs['readonly'] = True
        return form

    def get_subjects(self, obj):
        subjects = [obj.subject_1.name]
        if obj.subject_2:
            subjects.append(obj.subject_2.name)
        if obj.subject_3:
            subjects.append(obj.subject_3.name)
        return format_html(' + '.join(subjects))
    get_subjects.short_description = '考试科目'

    def get_status_with_color(self, obj):
        colors = {
            'preparing': 'blue',
            'in_progress': 'green',
            'finished': 'gray',
            'cancelled': 'red'
        }
        return format_html(
            '<span style="color: {};">{}</span>',
            colors.get(obj.status, 'black'),
            obj.get_status_display()
        )
    get_status_with_color.short_description = '考场状态'

    def get_question_counts(self, obj):
        return format_html(
            '单选:{}道({}分) | 多选:{}道({}分) | 判断:{}道({}分)',
            obj.single_choice_count, obj.single_choice_score,
            obj.multiple_choice_count, obj.multiple_choice_score,
            obj.judgment_count, obj.judgment_score
        )
    get_question_counts.short_description = '题目配置'

    def save_model(self, request, obj, form, change):
        try:
            # 检查题目数量是否足够
            error_messages = obj.check_questions_availability()
            if error_messages:
                for error in error_messages:
                    messages.error(request, error)
                return

            if not change:  # 如果是新创建的考场
                obj.status = 'preparing'  # 设置状态为"准备中"

            super().save_model(request, obj, form, change)

            # 创建定时任务
            if not change or obj.status == 'preparing':
                self.schedule_exam_tasks(obj)
                messages.success(request, '考场创建成功！题库中有足够的题目。')
            else:
                messages.success(request, '考场更新成功！题库中有足够的题目。')
        except Exception as e:
            messages.error(request, str(e))
            return

    @staticmethod
    def schedule_exam_tasks(exam_room):
        """为考场创建定时任务"""
        # 删除已存在的定时任务
        PeriodicTask.objects.filter(name__startswith=f'exam_{exam_room.id}_').delete()
        print("schedule_exam_tasks-from admin.py")

        # 1.创建考试开始前10秒的任务
        start_time = exam_room.start_time - timezone.timedelta(seconds=10)
        prepare_crontab = CrontabSchedule.objects.create(
            minute=str(start_time.minute),
            hour=str(start_time.hour),
            day_of_month=str(start_time.day),
            month_of_year=str(start_time.month),
        )
        PeriodicTask.objects.create(
            name=f'exam_{exam_room.id}_prepare',
            task='exam_system.tasks.prepare_exam_room',
            crontab=prepare_crontab,
            one_off=True,
            args=json.dumps([exam_room.id]),
            enabled=True
        )

        # 2.创建考试开始时的任务
        start_time = exam_room.start_time
        prepare_crontab = CrontabSchedule.objects.create(
            minute=str(start_time.minute),
            hour=str(start_time.hour),
            day_of_month=str(start_time.day),
            month_of_year=str(start_time.month),
        )
        PeriodicTask.objects.create(
            name=f'exam_{exam_room.id}_start',
            task='exam_system.tasks.start_exam_room',
            crontab=prepare_crontab,
            one_off=True,
            args=json.dumps([exam_room.id]),
            enabled=True
        )

        # 3.创建考试结束时的任务
        end_time = exam_room.start_time + timezone.timedelta(minutes=exam_room.duration)
        finish_crontab = CrontabSchedule.objects.create(
            minute=str(end_time.minute),
            hour=str(end_time.hour),
            day_of_month=str(end_time.day),
            month_of_year=str(end_time.month),
        )
        PeriodicTask.objects.create(
            name=f'exam_{exam_room.id}_finish',
            task='exam_system.tasks.finish_exam_room',
            crontab=finish_crontab,
            one_off=True,
            args=json.dumps([exam_room.id]),
            enabled=True
        )

    def get_status_with_color(self, obj):
        colors = {
            'preparing': 'blue',
            'in_progress': 'green',
            'finished': 'gray',
            'cancelled': 'red'
        }
        return format_html(
            '<span style="color: {};">{}</span>',
            colors.get(obj.status, 'black'),
            obj.get_status_display()
        )
    get_status_with_color.short_description = '考场状态'
